package pure.engine.core 
{
	import flash.display.Shape;
	import flash.events.Event;
	import flash.utils.getTimer;
	
	/**
	 * 延迟管理器
	 * [Author] - PURE
	 * 
	 */
final public class DelayManager
{
	
	
	/**
	 * 延迟回调
	 * 
	 * [Param] - delay     延迟时间(秒)
	 * [Param] - callback  回调方法
	 * [Param] - args      回调参数
	 * [Return] - 生成延迟对象的唯一识别
	 */
	public function delayedCall(delay:Number, callback:Function, ...args):int
	{
		var delayObject:DelayObject;
		
		if (delay < 0)
		{
			throw new Error('[DelayManager] >>>> ＃delayedCall', '延迟时间不可为负 !!');
		}
		
		if(!m_started)
		{
			trace('[DelayManager] >>>> 延迟管理器，启动... !!');
			
			m_shape.addEventListener(Event.ENTER_FRAME, _advance, false, 100000, true);
			m_started = true;
		}
		
		m_delayProp[++m_numDelay]  =  delayObject = DelayObject.getDelayObject();
		delayObject.delay          =  (delay * 1000.0 + getTimer() + 0.5) >> 0;
		delayObject.callback       =  callback;
		delayObject.params         =  args;
		delayObject.delayID        =  ++m_count;
		m_masterList[m_count]      =  delayObject;
		
		_doInsert(m_numDelay);
		return m_count;
	}

	
	/**
	 * 移除指定延迟回调
	 * 
	 * [Param] - delayID  延迟对象唯一识别
	 */
	public function removeDelayedCall(delayID:uint):void
	{
		var delayObject:DelayObject;
		var index:int;
		
		if (!m_masterList[delayID])
		{
			trace('[DelayManager] >>>> ＃removeDelayedCall >>>> 无法移除不存在的延迟对象...delayID(' + delayID + ')...!!');
			return;
		}
		
		delayObject = m_masterList[delayID];
		delete m_masterList[delayID];
		delayObject.recycle();
		
		// 仅一个
		if (--m_numDelay == 0)
		{
			m_shape.removeEventListener(Event.ENTER_FRAME, _advance);
			m_delayProp.length  =  1;
			m_started           =  false;
			
			trace('[DelayManager] >>>> 延迟管理器，移除后，全部结束...');
		}
		else
		{
			index = m_delayProp.indexOf(delayObject);
			// 末位
			if (index == m_numDelay + 1)
			{
				m_delayProp.pop()
			}
			else
			{
				m_delayProp[index] = m_delayProp.pop();
				_doSink(index);
			}
		}
	}
	
	
	/**
	 * 清零
	 */
	public function reset():void
	{
		trace('[DelayManager] >>>> 延迟管理器，清零...');
		
		m_shape.removeEventListener(Event.ENTER_FRAME, _advance);
		while (--m_numDelay > 0)
		{
			m_delayProp[m_numDelay].recycle();
		}
		
		m_masterList        =  { };
		m_delayProp.length  =  1;
		m_started           =  false;
	}
	
	
	/**
	 * 信息
	 * 
	 * [Return] - 当前延迟记录信息
	 */
	public function toString():String
	{
		var list:Array = [];
		var i:int, l:int;
		
		for (i = 1; i <= m_numDelay; i++) 
		{
			list.push(m_delayProp[i].delay * 0.001);
		}
		for (var t:* in m_masterList)
		{
			++l;
		}
		
		return '【DelayManager × ' + m_numDelay + '】 >>>> ' + list.join(',') + '...' + l;
	}

	
	
	
	/* ----------------------------------------------------------------------------------------------------------------
	 * ★★★★★★★★★★★★★★★★★★★★★  private  ★★★★★★★★★★★★★★★★★★★★★
	 * ----------------------------------------------------------------------------------------------------------------
	 */
	
	

	/**
	 * 移除并获取首项
	 * 
	 * [Return] - 延迟对象
	 * 
	 * [Feature] - ① 父节点 ---- prev = (N-1 / 2) >> 0
	 *             ② 子节点 ---- next = N*2+1 或 N*2+2
	 */
	private function _doShift():DelayObject
	{
		var result:DelayObject;
		
		if (--m_numDelay == 0) 
		{
			result = m_delayProp.pop();
		}
		else
		{
			result          =  m_delayProp[1];
			m_delayProp[1]  =  m_delayProp.pop();
			_doSink(1)
		}
		delete m_masterList[result.delayID];
		return result;
	}
	
	
	/**
	 * 插入
	 * 
	 * [Param] - index  加入项索引
	 * 
	 * [Hint] - ① N - 1 / 2 = N >> 1
	 *          ② 向上冒
	 */
	private function _doInsert(index:int):void
	{
		var delayObject:DelayObject;
		var prev:int;
		
		while (index > 1)
		{
			prev = index >> 1;
			if (m_delayProp[index].delay < m_delayProp[prev].delay)
			{
				delayObject         =  m_delayProp[index];
				m_delayProp[index]  =  m_delayProp[prev];
				m_delayProp[prev]   =  delayObject;
				index               =  prev;
			}
			else
			{
				break;
			}
		} 
	}
	
	
	/**
	 * 下沉
	 * 
	 * [Param] - index  下沉项索引
	 */
	private function _doSink(index:int):void
	{
		var delayObject:DelayObject;
		var index:int, oldIndex:int, next:int;
		
		while (true)
		{
			oldIndex  =  index;
			next      =  index * 2;
			
			if (next < m_numDelay + 1)
			{
				if (m_delayProp[index].delay > m_delayProp[next].delay)
				{
					index = next;
				}
				
				if (next < m_numDelay && m_delayProp[index].delay > m_delayProp[next + 1].delay)
				{
					index = next + 1;
				}
			}
			
			if (index != oldIndex)
			{
				delayObject            =  m_delayProp[index];
				m_delayProp[index]     =  m_delayProp[oldIndex];
				m_delayProp[oldIndex]  =  delayObject;
			}	
			else
			{
				break;
			}
		} 
	}
	
	
	
	
	//======================
	// Event
	//======================
	
	
	/**
	 * 更新
	 */
	private function _advance(e:Event):void
	{
		var delayObject:DelayObject;
		
		while (m_delayProp[1].delay <= getTimer())
		{
			delayObject = _doShift();
			delayObject.callback.apply(null, delayObject.params);
			delayObject.recycle();
			
			if (m_numDelay == 0)
			{
				trace('[DelayManager] >>>> 延迟管理器，全部结束...');
				m_shape.removeEventListener(Event.ENTER_FRAME, _advance);
				m_started = false;
				return;
			}
		}
	}
	
	
	
		
	//======================
	// Member
	//======================
	
	
	private static var m_shape:Shape = new Shape();
	
	private var m_delayProp:Vector.<DelayObject> = Vector.<DelayObject>([null]);
	
	private var m_masterList:Object = { };  //  delayID : DelayObject
	
	private var m_numDelay:int;  // 总数

	private var m_started:Boolean;

	private var m_count:uint;
	
}
}


final class DelayObject
{
	
	/**
	 * 获取
	 */
	public static function getDelayObject():DelayObject
	{
		return Boolean(cachedDelayLength > 0 ? cachedDelayLength-- : 0) ? cachedDelayList.pop() : new DelayObject();
	}
	
	
	/**
	 * 回收
	 */
	public function recycle():void
	{
		cachedDelayList[cachedDelayLength++] = this;
		callback  =  null;
		params    =  null;
	}
	
	
	
	
	//======================
	// Member
	//======================
	
	
	private static var cachedDelayList:Array = [];

	private static var cachedDelayLength:int;
	
	
	public var delay:int;  // 延迟时间
	
	public var callback:Function;  // 回调
	
	public var params:Array;  // 参数
	
	public var delayID:uint;  // 识别
	
}